﻿#region Creditos

/* Autor: Edilberto Sánchez Forero	*/
/* Email: esanchezfo@gmail.com		*/
/* Licencia: LGPL, Software Libre	*/
/* País: Colombia, Bogotá			*/

#endregion

#region Librerias

using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Xml;
using ESF.General.Entity;
using System.Text;
using System.Linq;
using System.Linq.Expressions;
using System.Collections;
using System.Collections.Specialized;
using System.Globalization;

#endregion


namespace ESF.General
{
	public static class DataHelper
	{
		#region Constantes
		
		public const string COLUMNCOUNTNAME = "RCount";
		
		#endregion


		#region Delegados

		public delegate O GetObjectFromDataReader<O>(IDataReader pOpenedDatareader, string pPrefix = "", string pListLoading = "");

		public delegate O GetObjectFromDataRow<O>(DataRow pRow, string pPrefix = "", string pListLoading = "");

		#endregion
	

		#region Streams

		public static void Clear(Stream pData)
		{
			pData.SetLength(0);

			pData.Position = 0;
		}


		/// <summary>
		/// Copies one stream into another.
		/// </summary>
		public static void CopyToStream (this Stream input, Stream output)
		{
			byte[] buffer = new byte[16 * 1024]; // Fairly arbitrary size
			int bytesRead;

			while ((bytesRead = input.Read(buffer, 0, buffer.Length)) > 0)
			{
				output.Write(buffer, 0, bytesRead);
			}
		}

		#endregion
		

		#region Extensions

		public static IEnumerable<O> GetDataRecord<O>(this IDataReader pOpenedDatareader, GetObjectFromDataReader<O> pdelGetObjectFromDataReader, string pPrefix = "", string pListLoading = "")
		{
			if (pOpenedDatareader == null)
			{
				throw new ArgumentNullException("pSource");
			}

			while (pOpenedDatareader.Read())
			{
				yield return pdelGetObjectFromDataReader(pOpenedDatareader, pPrefix, pListLoading);
			}
		}

		#endregion

	
		#region Limpieza

		public static void RemoveAtLastEmptyRow (ref DataTable pTable)
		{
			int rowIndex;

			bool rowEmpty;


			if (IsEmpty (pTable)) { return; }

			for (rowIndex = 0; rowIndex < pTable.Rows.Count; rowIndex ++)
			{
				rowEmpty = true;
				
				for (int colIndex = 0; colIndex < pTable.Columns.Count; colIndex ++)
				{
					rowEmpty &= TextHelper.IsEmpty (pTable.Rows [rowIndex][colIndex].ToString ());

					if (!rowEmpty)
					{
						break;
					}
				}

				if (rowEmpty)
				{
					break;
				}
			}

			for (;rowIndex < pTable.Rows.Count; rowIndex ++)
			{
				pTable.Rows.RemoveAt (rowIndex);
				rowIndex --;
			}
		}


		public static void RemoveEmptyColumns (ref DataTable pTable)
		{
			bool columnEmpty;


			if (IsEmpty (pTable)) { return; }

			for (int colIndex = 0; colIndex < pTable.Columns.Count; colIndex ++)
			{
				columnEmpty = true;

				for (int rowIndex = 0; rowIndex < pTable.Rows.Count; rowIndex ++)
				{
					columnEmpty &= TextHelper.IsEmpty (pTable.Rows [rowIndex][colIndex].ToString ());
					
					if (!columnEmpty)
					{
						break;
					}
				}

				if (columnEmpty)
				{
					pTable.Columns.RemoveAt (colIndex);
					colIndex --;
				}
			}
		}

		#endregion


		#region Comparacion

		public static bool BasicAreDifferent<T> (List<T> pCurrent, List<T> pOriginal)
		{
			if (pCurrent == null && pOriginal == null) { return false; }

			if (pCurrent == null || pOriginal == null) { return true; }

			if (pOriginal.Count != pCurrent.Count) { return true; }

			return false;
		}


		public static bool AreDifferent<T>(List<T> pCurrent, List<T> pOriginal) where T : IEquatable<T>
		{
			if (BasicAreDifferent<T> (pCurrent, pOriginal)) { return true; }

			foreach (T actual in pCurrent)
			{
				if (!pOriginal.Exists (o=>o.Equals (actual)))
				{
					return false;
				}
			}

			return false;
		}

		#endregion


		#region Ajuste

		public static DateTime? SetAsStartDate (DateTime? pStartDate)
		{
			if (pStartDate == null) { return null; }

			return new DateTime (pStartDate.Value.Year, pStartDate.Value.Month, pStartDate.Value.Day, 0, 0, 0);
		}


		public static DateTime? SetAsEndDate (DateTime? pStartDate)
		{
			if (pStartDate == null) { return null; }

			return new DateTime (pStartDate.Value.Year, pStartDate.Value.Month, pStartDate.Value.Day, 23, 59, 59);
		}

		#endregion


		#region Null

		public static bool IsNullable<T>(T obj)
		{
			if (obj == null) return true; // obvious
			Type type = typeof(T);
			if (!type.IsValueType) return true; // ref-type
			if (Nullable.GetUnderlyingType(type) != null) return true; // Nullable<T>
			return false; // value-type
		}

		#endregion


		#region Conversion
		
		public static string ConcatenateNames<BR> (string pSeparator, List<BR> pList) where BR : BasicReference
		{
			StringBuilder result;


			if (IsEmpty (pList)) { return string.Empty; }

			result = new StringBuilder();

			foreach (BR item in pList)
			{
				result.AppendFormat ("{0}{1}", item.Name, pSeparator);
			}

			result.Length -= pSeparator.Length;

			return result.ToString ();
		}


		public static KeyValuePair<A,B> [] ToArray<A,B> (Dictionary <A,B> pDic)
		{
			List<KeyValuePair<A, B>> confValues;


			if (pDic == null) { return null; }

			confValues = new List<KeyValuePair<A, B>>();

			foreach (KeyValuePair<A, B> item in pDic)
			{
				confValues.Add(item);
			}

			return confValues.ToArray();
		}


		public static string BasicVectorConverter(DataRow pRow, string pPrefix = "", string pListLoading = "")
		{
			if (pRow == null) { return null; }

			return pRow [0].ToString ();
		}


		public static string BasicVectorConverter(IDataReader pReader, string pPrefix = "", string pListLoading = "")
		{
			if (pReader == null) { return null; }

			return pReader.GetValue (0).ToString ();
		}


		public static string ToStringDbReaderItem (IDataReader pReader, int pItemIndex, params string [] pReplaces)
		{
			object value;


			if (pReader == null) { return null; }

			value = pReader.GetValue (pItemIndex);

			if (value == null) { return null; }

			if (value is double || value is float || value is int || value is uint 
				|| value is ushort || value is short || value is long || value is ulong 
				|| value is decimal)
			{
				return string.Format ("{0:0.##}", value);
			}

			return TextHelper.ReplaceAll (value.ToString (), string.Empty, pReplaces);
		}


		public static string [] ConvertToStringArray<O> (BrowseResults<O> pList)
		{
			return ConvertToStringArray <O> (pList, "Name");
		}
		
		
		public static string [] ConvertToStringArray<O> (BrowseResults<O> pList, string pFieldName)
		{
			if (IsEmpty (pList)) { return null; }
			
			return ConvertToStringArray <O> (pList.Results, pFieldName).ToArray ();
		}
		
		
		public static string [] ConvertToStringArray<O> (IEnumerable<O> pList)
		{
			return ConvertToStringArray<O> (pList, "Name").ToArray ();
		}
		
		
		public static string [] ConvertToStringArray<O> (IEnumerable<O> pList, string pFieldName)
		{
			List<string> result;
			
		
			if (pList == null)
			{
				return null;
			}
			
			result = new List<string> ();
			
			foreach (O item in pList)
			{
				result.Add(item.GetType().GetProperty(pFieldName).GetValue(item, null) as string);
			}
			
			return result.ToArray ();
		}
		
		
		public static BrowseResults<O> ConvertToPaged<O> (List<O> pItems, int pPageSize, int pPageIndex)
		{
			return ConvertToPaged <O> (pItems, new PaggingInfo () { PageSize = pPageSize, PageIndex = pPageIndex });
		}
		

		public static BrowseResults<O> ConvertToPaged<O>(List<O> pItems, PaggingInfo pPaggingInfo)
		{
			BrowseResults<O> result;

			List<O> temp = new List<O> ();
			
		
			if (IsEmpty (pItems)) { return null; }
		
			result = new BrowseResults<O> ();
			
			for (int i = pPaggingInfo.PageIndex * pPaggingInfo.PageSize;
				i < pPaggingInfo.PageIndex * pPaggingInfo.PageSize + pPaggingInfo.PageSize && i < pItems.Count; i++)
			{
				temp.Add (pItems [i]);
			}
			
			result.Results = temp;

			pPaggingInfo.RowCount = pItems.Count;
			
			result.PaggingInfo = pPaggingInfo;
			
			return result;
		}
		

		#region Convert BR

		public static AE ConvertToAuditableEntity<AE>(IDataReader pReader, string pPrefix = "", string pListLoading = "")
			where AE : IAuditableEntity, new()
		{
			if (pReader == null) { return default(AE); }

			return new AE()
			{
				CreationDateTime = GetNullableDateTime(pReader, pPrefix + "CreationDateTime"),
				LastUpdateDateTime = GetNullableDateTime(pReader, pPrefix + "LastUpdateDateTime"),
				UserCreationAlias = GetString(pReader, pPrefix + "UserCreationAlias"),
				UserLastUpdateAlias = GetString(pReader, pPrefix + "UserLastUpdateAlias")
			};
		}

		public static UserMenuItem ConvertToUserMenuItem(IDataReader pReader, string pPrefix = "", string pListLoading = "")
		{
			UserMenuItem item;


			item = ConvertToBasicReference<UserMenuItem>(pReader, pPrefix);

			if (item == null) { return null; }

			item.URL = GetString(pReader, pPrefix + "URL");
			item.calMarked = GetBool(pReader, pPrefix + "calMarked", false);

			item.Application = ConvertToDirectBasicReference(pReader, pPrefix + "Application_");

			if (GetNullableInt(pReader, pPrefix + "ParentID") != null)
			{
				item.Parent = new UserMenuItem() { ID = GetNullableInt(pReader, pPrefix + "ParentID"), Code = GetString(pReader, pPrefix + "ParentCode") };
			}

			return item;
		}


		public static TreeBasicReference ConvertToTreeBasicReference(IDataReader pReader, string pPrefix = "", string pListLoading = "")
		{
			return new TreeBasicReference ()
			{
				ID = GetInt (pReader, pPrefix + "Tree_ID"),
				Parent = ConvertToDirectBasicReference (pReader, pPrefix + "ParBR_"),
				Child = ConvertToDirectBasicReference (pReader, pPrefix + "ChiBR_"),
				Value = GetString (pReader, pPrefix + "Value")
			};
		}


		public static BasicReference ConvertToDirectBasicReference(IDataReader pReader, string pPrefix = "", string pListLoading = "")
		{
			return ConvertToBasicReference <BasicReference> (pReader, pPrefix, pListLoading);
		}
		
		
		public static BR ConvertToBasicReference<BR> (IDataReader pReader, string pPrefix = "", string pListLoading = "") where BR : BasicReference, new ()
		{
			BR basRef;
		
		
			basRef = new BR ()
			{			
				ID = GetNullableInt (pReader, pPrefix + "ID"),
				Code = GetString(pReader, pPrefix + "Code"),
				Name = GetString(pReader, pPrefix + "Name"),
				Description = GetString (pReader, pPrefix + "Description"),
				Extra_I = GetString (pReader, pPrefix + "Extra_I"),
				Extra_II = GetString (pReader, pPrefix + "Extra_II"),
				Extra_III = GetString (pReader, pPrefix + "Extra_III"),
				Value = GetString (pReader, pPrefix + "Value"),
				IsEnabled = GetBool (pReader, pPrefix + "IsEnabled", false),
				CreationDateTime = GetNullableDateTime (pReader, pPrefix + "CreationDateTime"),
				LastUpdateDateTime = GetNullableDateTime (pReader, pPrefix + "LastUpdateDateTime"),
				UserCreationAlias = GetString (pReader, pPrefix + "CreationAlias"),
				UserLastUpdateAlias = GetString (pReader, pPrefix + "LastUpdateAlias"),

				calRowIndex = DataHelper.GetInt (pReader, pPrefix + "Ri"),
				calVirtualRowCount = DataHelper.GetInt (pReader, pPrefix + "RCount")
			};
			
			if (!IsNull (pReader, pPrefix + "BasicReferenceTypeID"))
			{
				basRef.BasicReferenceType = new BasicReferenceType () { ID = Convert.ToInt32 (pReader [pPrefix + "BasicReferenceTypeID"]) };
			}
			
			return basRef;
		}

		#endregion


		public static bool IsEmptyRef<BR> (BR pItem) where BR : BasicReference
		{
			return (pItem == null || (pItem.ID == null && TextHelper.IsEmpty (pItem.Code) && TextHelper.IsEmpty (pItem.Name)));
		}
		
		
		public static bool IsEmpty (DataRow pRow, string pColumnName)
		{
			return pRow == null || pRow.Table == null || pRow.Table.Columns [pColumnName] == null || pRow.IsNull (pColumnName);
		}


		public static bool IsEmpty (DataRowView pRow, string pColumnName)
		{
			return (pRow == null || IsEmpty (pRow.Row, pColumnName));
		}
	
	
		public static string DataTableToXLS (DataTable pTable)
		{
			return DataTableToXLS (pTable, 120);
		}
		
		public static string DataTableToXLS (DataTable pTable, int pColumnWidth)
		{
			XmlWriter xmlWriter;
			
			StringBuilder stbXLS;
			
			
			if (IsEmpty (pTable)) { return null; }
			
			
			stbXLS = new StringBuilder ();
			
			xmlWriter = XmlWriter.Create (stbXLS, new XmlWriterSettings() { ConformanceLevel = ConformanceLevel.Fragment, OmitXmlDeclaration = true, Indent = false });
			
			
			xmlWriter.WriteRaw(@"<html xmlns:v=""urn:schemas-microsoft-com:vml"" xmlns:o=""urn:schemas-microsoft-com:office:office"" xmlns:x=""urn:schemas-microsoft-com:office:excel"" xmlns=""http://www.w3.org/TR/REC-html40"">
				<head>
					<meta http-equiv=""Content-Type"" content=""text/html; charset=windows-1252"" />
					<meta name=""ProgId"" content=""Excel.Sheet"" />
					<meta name=""Generator"" content=""Microsoft Excel 12"" />
				</head><body><table border=""1"" bordercolor""#CACACA"">");
			
			xmlWriter.WriteStartElement ("tr");
			xmlWriter.WriteAttributeString ("style", string.Format ("width: {0}px; border-bottom: solid 1px black;font-weight: bold;background-color:black; color:White;", pColumnWidth));
			
			foreach (DataColumn col in pTable.Columns)
			{
				xmlWriter.WriteElementString ("th", col.ColumnName);
			}
			
			xmlWriter.WriteEndElement ();
			xmlWriter.Flush();
			
			foreach(DataRow row in pTable.Rows)
			{
				xmlWriter.WriteStartElement ("tr");
			
				for (int i = 0; i < pTable.Columns.Count; i++)
				{
					xmlWriter.WriteStartElement ("td");
					
					if (row [i] != null || row [i] != DBNull.Value)
					{					
						xmlWriter.WriteString (row [i].ToString ());
					}
					
					xmlWriter.WriteEndElement ();
				}
				
				xmlWriter.WriteEndElement ();
			}
			
			
			xmlWriter.WriteRaw ("</table></body></html>");
			
			xmlWriter.Close ();
			
			return stbXLS.ToString ();
		}
	
		#endregion
		
		
		#region Get Objects
		
		public static int? GetID (BasicReference pBasRef)
		{
			if (pBasRef == null) { return null; }
		
			return pBasRef.ID;
		}
		
		
		public static O Get<O> (DataRow pRow, GetObjectFromDataRow<O> pConvertTo)
		{
			return Get<O> (pRow, pConvertTo, string.Empty);
		}
		
		
		public static O Get<O> (DataRow pRow, GetObjectFromDataRow<O> pConvertTo, string pPrefix)
		{
			if (pRow == null) { return default (O); }
		
			return pConvertTo (pRow, pPrefix);
		}
			
		#endregion
	
	
		#region Obtener Conteo de Filas
		
		public static int GetValueForVirtualColumnCount (DataTable pTable)
		{
			return GetValueForVirtualColumnCount (GetFirstRow (pTable));
		}
		
		
		public static int GetValueForVirtualColumnCount (DataTable pTable, string pVirtualColumnCountName)
		{
			return GetValueForVirtualColumnCount (GetFirstRow (pTable), pVirtualColumnCountName);
		}
		
		
		public static int GetValueForVirtualColumnCount (DataRow pRow)
		{
			return GetValueForVirtualColumnCount (pRow, COLUMNCOUNTNAME);
		}
		
		
		public static int GetValueForVirtualColumnCount (DataRow pRow, string pVirtualColumnCountName)
		{
			return GetInt (pRow, pVirtualColumnCountName, 0);
		}
		
		#endregion
		
		
		#region Get Data
		
		public static DataTable GetFirstDataTable(DataSet pSet)
		{
			return GetDataTable (pSet, 0);
		}
	
	
		public static DataTable GetDataTable (DataSet pSet, int pTableIndex)
		{
			DataTable resultado;


			if (IsEmpty (pSet) || pSet.Tables.Count < pTableIndex + 1)
			{
				return null;
			}
			
			resultado = pSet.Tables [pTableIndex];
			
			if (IsEmpty (resultado))
			{
				return null;
			}
			
			return resultado;
		}
		
		
		public static DataSet ToDataSet (string pXMLTables)
		{
			DataSet dtsSet;
			
			
			dtsSet = new DataSet ();
			
			dtsSet.ReadXml (new XmlTextReader (new StringReader (pXMLTables)));
			
			
			return dtsSet;
		}
	
	
		public static DataSet ToDataSet (DataRow pRow)
		{
			DataTable dtbTabla;
			
		
			if (pRow == null) { return null; }
			
			if (pRow.Table != null) 
			{
				return ToDataSet (pRow.Table);
			}
			
			dtbTabla = new DataTable ();
			
			dtbTabla.Rows.Add (pRow);
			
			return ToDataSet (dtbTabla);
		}
		
		
		public static DataSet ToDataSet (DataTable pdtbTabla)
		{
			DataSet dtsSet;
			
			
			if (IsEmpty (pdtbTabla)) { return null; }
			
			if (pdtbTabla.DataSet != null) { return pdtbTabla.DataSet; }
			
			dtsSet = new DataSet ();
			pdtbTabla.AcceptChanges ();
			dtsSet.Tables.Add (pdtbTabla);
			
			return dtsSet;
		}
		
		
		public static DataRow GetFirstRow (DataSet pdtsSet)
		{
			return GetFirstRow (GetFirstDataTable (pdtsSet));
		}
		
		
		public static DataRow GetFirstRow (DataTable pdtbTabla)
		{
			if (IsEmpty (pdtbTabla)) { return null; }
			
			pdtbTabla.AcceptChanges ();
			
			return pdtbTabla.Rows [0];
		}


		public static bool IsEmpty<O> (List <O> pItems)
		{
			return (pItems == null || pItems.Count == 0);
		}


		public static bool IsEmpty<O> (IList <O> pItems)
		{
			return (pItems == null || pItems.Count == 0);
		}


		public static bool IsEmpty<key, value> (IDictionary <key, value> pItems)
		{
			return (pItems == null || pItems.Count == 0);
		}


		public static bool IsEmpty<key, value>(Dictionary<key, value> pItems)
		{
			return (pItems == null || pItems.Count == 0);
		}


		public static bool IsEmpty<O> (O pItems) where O : CollectionBase
		{
			return (pItems == null || pItems.Count == 0);
		}


		public static bool IsEmpty (DataRow pRow)
		{
			return (pRow == null);
		}


		public static bool IsEmpty(NameValueCollection pItems) 
		{
			return (pItems == null || pItems.Count == 0);
		}


		public static bool IsEmpty<O> (IEnumerable<O> pItems)
		{
			return (pItems == null || pItems.Count () == 0);
		}


		public static bool IsEmpty (object pItem)
		{
			return (pItem == null);
		}


		public static bool IsNullOrEmpty<T>(this IEnumerable<T> pEnum)
		{
			return pEnum == null || !pEnum.Any();
		}


		public static bool IsEmpty<O> (params O [] pItems)
		{
			return (pItems == null || pItems.Length == 0);
		}

		
		public static bool IsEmpty<O> (BrowseResults <O> pResults)
		{
			return (pResults == null || pResults.Results.IsNullOrEmpty ());
		}
		
		
		public static bool IsEmpty (DataSet pdtsSet)
		{
			return (pdtsSet == null || pdtsSet.Tables.Count == 0);
		}
		
		
		public static bool IsEmpty (DataTable pdtbTabla)
		{
			return (pdtbTabla == null || pdtbTabla.Rows.Count == 0);
		}


		public static List<string> GetStringVector (DataRow [] pRows, string pColumnName)
		{
			return GetStringVector (pRows, pColumnName, null);
		}


		public static List<string> GetStringVector (DataRow [] pRows, string pColumnName, Func<string, string> pTransformItems)
		{
			List<string> result;


			result = new List<string> ();

			if (IsEmpty (pRows)) { return result; }

			foreach (DataRow item in pRows)
			{
				if (pTransformItems != null)
				{
					result.Add(pTransformItems (item[pColumnName].ToString()));
				}
				else
				{
					result.Add (item [pColumnName].ToString ());
				}
			}

			return result;
		}
		

		public static List<string> GetStringVector (DataTable pdtbTabla)
		{
			if (IsEmpty (pdtbTabla)) { return null; }
			
			return GetStringVector (pdtbTabla, pdtbTabla.Columns [0].ColumnName);
		}
		
		
		public static List<string> GetStringVector (DataTable pdtbTabla, string pstrNombreColumna)
		{
			List <string> strVector;
		
		
			if (IsEmpty (pdtbTabla)) { return null; }
			
			strVector = new List<string> (pdtbTabla.Rows.Count);
			
			foreach (DataRow dtrFila in pdtbTabla.Rows)
			{
				if (!dtrFila.IsNull (pstrNombreColumna))
				{
					if (dtrFila.IsNull (pstrNombreColumna))
					{
						strVector.Add (null);
					}
					else
					{
						strVector.Add(dtrFila[pstrNombreColumna] as string);
					}
				}
			}
			
			return strVector;
		}
		
		#endregion
		

		#region Take

		public delegate bool IndexIf (int pIndex);


		public static O [] TakeByIndex<O> (IndexIf pIndexCondition, params O [] pItems)
		{
			List<O> result;


			if (IsEmpty (pItems)) { return null; }

			result = new List<O> ();

			for (int i = 0; i < pItems.Length; i++)
			{
				if (pIndexCondition (i))
				{
					result.Add (pItems [i]);
				}
			}

			return result.ToArray ();
		}


		public static List<O> TakeByIndex<O> (IndexIf pIndexCondition, List<O> pItems)
		{
			List<O> result;


			if (IsEmpty (pItems)) { return null; }

			result = new List<O> ();

			for (int i = 0; i < pItems.Count; i++)
			{
				if (pIndexCondition (i))
				{
					result.Add (pItems [i]);
				}
			}

			return result;
		}

		#endregion

		
		#region Escalar
		
		public static object GetFirstObject (DataSet pConjuntoTablas)
		{
			if (IsEmpty (pConjuntoTablas))
			{
				return null;
			}
			
			return GetFirstObject (GetFirstRow (pConjuntoTablas));
		}
		
		
		public static object GetFirstObject (DataTable pTabla)
		{
			if (IsEmpty (pTabla))
			{
				return null;
			}
			
			return GetFirstObject (GetFirstRow (pTabla));
		}		

		#endregion


		#region Gets from IDataReader

		public static bool IsNull(this IDataReader pReader, string pColName)
		{
			try
			{
				return pReader == null || pReader.IsDBNull(pReader.GetOrdinal(pColName));
			}
			catch (IndexOutOfRangeException)
			{
				return true;
			}
		}


		public static bool IsNull(this DataRow pRow, string pColName)
		{
			return pRow == null || pRow.IsNull (pColName);
		}


		public static object GetFirstObject(IDataReader pReader)
		{
			if (pReader.IsDBNull(0)) { return null; }

			return pReader.GetValue(0);
		}


		public static decimal GetDecimal(IDataReader pReader, string pColumna)
		{
			return GetDecimal(pReader, pColumna, 0);
		}


		public static decimal GetDecimal(IDataReader pReader, string pColumna, decimal pNullValue)
		{
			return pReader.GetValue<decimal> (pColumna, pNullValue);
		}


		public static decimal? GetNullableDecimal(IDataReader pReader, string pColumna, decimal? pNullValue = null)
		{
			return pReader.GetValue<decimal?> (pColumna, pNullValue);
		}


		public static double GetDouble(IDataReader pReader, string pColumna)
		{
			return GetDouble(pReader, pColumna, 0);
		}


		public static double GetDouble(IDataReader pReader, string pColumna, double pNullValue)
		{
			return pReader.GetValue<double>(pColumna, pNullValue);
		}


		public static double? GetNullableDouble(IDataReader pReader, string pColumna, double? pNullValue = null)
		{
			return pReader.GetValue<double?>(pColumna, pNullValue);
		}

		
		public static int GetInt(IDataReader pReader, string pColumna, int pNullValue = 0)
		{
			return pReader.GetValue<int>(pColumna, pNullValue);
		}

		public static int? GetNullableInt(IDataReader pReader, string pColumna, int? pNullValue = null)
		{
			return pReader.GetValue<int?>(pColumna, pNullValue);
		}


		public static BasicReference GetAsBasicReferenceID(IDataReader pReader, string pColumna)
		{
			int? ID;


			ID = GetNullableInt(pReader, pColumna);

			if (ID == null)
			{
				return null;
			}

			return new BasicReference() { ID = ID };
		}


		public static BasicReference GetAsBasicReferenceCode (IDataReader pReader, string pColumna)
		{
			string code;


			code = GetString (pReader, pColumna);

			if (string.IsNullOrWhiteSpace (code))
			{
				return null;
			}

			return new BasicReference() { Code = code };
		}


		public static DateTime GetDateTime(IDataReader pReader, string pColumna)
		{
			return pReader.GetValue<DateTime> (pColumna);
		}


		public static DateTime GetDateTime(IDataReader pReader, string pColumna, string pFormat = TextHelper.DEFAULT_DATETIME_LONGFORMAT)
		{
			string result;

			
			result = GetString (pReader, pColumna);

			return DateTime.ParseExact(result, pFormat, CultureInfo.InvariantCulture);
		}


		public static DateTime GetDateTime(IDataReader pReader, string pColumna, DateTime pNullValue)
		{
			return pReader.GetValue<DateTime> (pColumna, pNullValue);
		}


		public static DateTime? GetNullableDateTime(IDataReader pReader, string pColumna)
		{
			return pReader.GetValue<DateTime?>(pColumna);
		}


		public static DateTime? GetNullableDateTime(IDataReader pReader, string pColumna, string pFormat = TextHelper.DEFAULT_DATETIME_LONGFORMAT)
		{
			string result;

			
			result = GetString (pReader, pColumna);

			if (string.IsNullOrWhiteSpace (result))
			{
				return null;
			}

			return DateTime.ParseExact(result, pFormat, CultureInfo.InvariantCulture);
		}


		public static long GetLong (IDataReader pReader, string pColumna, long pDefaultNullValue = 0)
		{
			return pReader.GetValue<long> (pColumna, pDefaultNullValue);
		}


		public static long? GetNullableLong(IDataReader pReader, string pColumna, long? pDefaultNullValue = null)
		{
			return pReader.GetValue<long?>(pColumna, pDefaultNullValue);
		}


		public static byte GetByte(IDataReader pReader, string pColumna, byte pNullValue = 0)
		{
			return pReader.GetValue <byte> (pColumna, pNullValue);
		}


		public static byte? GetNullableByte(IDataReader pReader, string pColumna, byte? pDefaultNullValue = null)
		{
			return pReader.GetValue<byte?> (pColumna, pDefaultNullValue);
		}


		public static bool GetBool(IDataReader pReader, string pColumna, bool pNullValue = false)
		{
			if (IsNull(pReader, pColumna)) { return pNullValue; }

			return TextHelper.GetBool (Convert.ToString(pReader[pColumna]));
		}


		public static bool? GetNullableBool(IDataReader pReader, string pColumna, bool? pNullValue = null)
		{
			if (IsNull(pReader, pColumna)) { return pNullValue; }

			return TextHelper.GetBool(Convert.ToString(pReader[pColumna]), (pNullValue == null ? false : pNullValue.Value));
		}

		#endregion


		#region XML

		public static string GetAttribute (XmlNode pNode, string pAttributeName, string pDefautValue = null)
		{
			if (pNode == null) { return pDefautValue; }

			if (pNode.Attributes [pAttributeName] == null) { return pDefautValue; }

			return pNode.Attributes [pAttributeName].Value;
		}


		public static string GetElement(XmlNode pNode, string pElementName, string pDefautValue = null)
		{
			if (pNode == null) { return pDefautValue; }

			if (pNode [pElementName] == null) { return pDefautValue; }

			return pNode [pElementName].InnerText;
		}

		#endregion


		#region Reader Extension

		public static bool HasColumn (this IDataRecord pRow, string pColumnName)
		{
			for (int i = 0; i < pRow.FieldCount; i++)
			{
				if (pRow.GetName (i).Equals (pColumnName, StringComparison.InvariantCultureIgnoreCase))
				{
					return true;
				}
			}

			return false;
		}


		public static T GetValue<T>(this IDataRecord pRow, string pColumnName, T pDefaultNullValue = default(T), List<string> pColumnNames = null)
		{
			if (!pRow.HasColumn (pColumnName))
			{
				return pDefaultNullValue;
			}

			if (IsEmpty (pColumnNames))
			{
				return pRow.GetValue<T> (pRow.GetOrdinal(pColumnName), pDefaultNullValue);
			}

			return pRow.GetValue<T>(pColumnNames.IndexOf (pColumnName), pDefaultNullValue);
		}


		public static T GetValue<T>(this IDataRecord pRow, int pOrdinal, T pDefaultNullValue = default(T))
		{
			object value;


			if (pRow.IsDBNull(pOrdinal))
			{
				return pDefaultNullValue;
			}

			value = pRow.GetValue(pOrdinal);

			try
			{
				if (value.GetType () != typeof (T))
				{
					if ((value is Int64 || value is Int64?)
					&& (typeof(T) == typeof(Int32?) || typeof(T) == typeof(Int32)))
					{
						return (T)(object)Convert.ToInt32(value);
					}
					else if (typeof (T) == typeof (string))
					{
						return (T)(object)Convert.ToString (value);
					}
				}

				return (T) value;
			}
			catch (Exception pEx)
			{
				throw new Exception (string.Format ("Type from DB is {0} for {1} [{2}] but required was {3} with value {4}", 
					value.GetType (), pRow.GetName (pOrdinal), pOrdinal, typeof (T), value.ToString ()), pEx);
			}
		}


		public static string GetString (IDataReader pReader, string pColumn, string pNullDefaultValue = null)
		{
			return pReader.GetValue<string> (pColumn, pNullDefaultValue);
		}


		public static XmlDocument GetXml(IDataReader pReader, string pColumn, string pUseMainElement = null)
		{
			string xmlContents;

			XmlDocument result;


			xmlContents = GetString (pReader, pColumn);

			if (string.IsNullOrWhiteSpace (xmlContents))
			{
				return null;
			}

			if (pUseMainElement != null)
			{
				xmlContents = "<" + pUseMainElement + ">" + xmlContents + "</" + pUseMainElement + ">";
			}

			result = new XmlDocument ();

			result.LoadXml (xmlContents);

			return result;
		}

		#endregion


		#region Gets from DataRow
		
		public static object GetFirstObject (DataRow pRow)
		{
			if (pRow == null) { return null; }
			
			return pRow [0];
		}
		

		public static decimal GetDecimal (DataRow pRow, string pColumna)
		{
			return GetDecimal (pRow, pColumna, 0);
		}

		
		public static decimal GetDecimal (DataRow pRow, string pColumna, decimal pNullValue)
		{
			object result;
		
		
			if (GetValue (pRow, pColumna, out result))
			{
				try
				{
					return Convert.ToDecimal (result);
				}
				catch (Exception)
				{
					return pNullValue;
				}
			}
			
			return pNullValue;
		}
		
		
		public static decimal? GetNullableDecimal (DataRow pRow, string pColumna)
		{
			object result;
		
		
			if (GetValue (pRow, pColumna, out result))
			{
				try
				{
					return Convert.ToDecimal (result);
				}
				catch (Exception)
				{
					return null;
				}
			}
			
			return null;
		}
		

		public static double GetDouble (DataRow pRow, string pColumna)
		{
			return GetDouble (pRow, pColumna, 0);
		}

		
		public static double GetDouble (DataRow pRow, string pColumna, double pNullValue)
		{
			object result;
		
		
			if (GetValue (pRow, pColumna, out result))
			{
				try
				{
					Convert.ToDouble (result);
				}
				catch (Exception)
				{
					return pNullValue;
				}
			}
			
			return pNullValue;
		}
		
		
		public static double? GetNullableDouble (DataRow pRow, string pColumna)
		{
			object result;
		
		
			if (GetValue (pRow, pColumna, out result))
			{
				try
				{
					return Convert.ToDouble (result);
				}
				catch (Exception)
				{
					return null;
				}
			}
			
			return null;
		}
		
		
		public static int GetInt (DataRow pRow, string pColumna, int pNullValue = 0)
		{
			object result;
		
		
			if (GetValue (pRow, pColumna, out result))
			{
				try
				{
					return Convert.ToInt32 (result);
				}
				catch (Exception)
				{
					return pNullValue;
				}
			}
			
			return pNullValue;
		}


		public static BasicReference GetAsBasicReferenceID (DataRow pRow, string pColumna)
		{
			int? ID;


			ID = GetNullableInt (pRow, pColumna);

			if (ID == null)
			{
				return null;
			}

			return new BasicReference () { ID = ID };
		}


		public static BasicReference GetAsBasicReferenceCode(DataRow pRow, string pColumna)
		{
			string code;


			code = GetString(pRow, pColumna);

			if (string.IsNullOrWhiteSpace(code))
			{
				return null;
			}

			return new BasicReference() { Code = code };
		}
		
		
		public static int? GetNullableInt (DataRow pRow, string pColumna)
		{
			object result;
		
		
			if (GetValue (pRow, pColumna, out result))
			{
				try
				{
					return Convert.ToInt32 (result);
				}
				catch (Exception)
				{
					return null;
				}
			}
			
			return null;
		}
		
		
		public static DateTime GetDateTime (DataRow pRow, string pColumna, DateTime pNullValue)
		{
			object result;
		
		
			if (GetValue (pRow, pColumna, out result))
			{
				try
				{
					return Convert.ToDateTime (result);
				}
				catch (Exception)
				{
					return pNullValue;
				}
			}
			
			return pNullValue;
		}


		public static DateTime GetDateTime(DataRow pRow, string pColumna)
		{
			object result;


			if (GetValue(pRow, pColumna, out result))
			{
				return Convert.ToDateTime(result);
			}

			throw new Exception (string.Format ("Column {0} invalid", pColumna));
		}
		
		
		public static DateTime? GetNullableDateTime (DataRow pRow, string pColumna)
		{
			object result;
		
		
			if (GetValue (pRow, pColumna, out result))
			{
				try
				{
					return Convert.ToDateTime (result);
				}
				catch (Exception)
				{
					return null;
				}
			}
			
			return null;
		}


		public static string GetDateTime(DataRow pRow, string pColumnName, string pFormat = TextHelper.DEFAULT_DATETIME_LONGFORMAT)
		{
			DateTime? value;


			value = GetNullableDateTime(pRow, pColumnName);

			if (value != null)
			{
				return value.Value.ToString(pFormat);
			}

			return string.Empty;
		}
		
		
		public static long GetLong (DataRow pRow, string pColumna, long pNullValue)
		{
			object result;
		
		
			if (GetValue (pRow, pColumna, out result))
			{
				try
				{
					return Convert.ToInt64 (result);
				}
				catch (Exception)
				{
					return pNullValue;
				}
			}
			
			return pNullValue;
		}
		
		
		public static long? GetNullableLong (DataRow pRow, string pColumna)
		{
			object result;
		
		
			if (GetValue (pRow, pColumna, out result))
			{
				try
				{
					return Convert.ToInt64 (result);
				}
				catch (Exception)
				{
					return null;
				}
			}
			
			return null;
		}
		
		
		public static string GetString (DataRow pRow, string pColumna)
		{
			return GetString (pRow, pColumna, null);
		}


		public static string GetString(DataRow pRow, string pColumna, string pDefaultValue)
		{
			if (IsEmpty (pRow, pColumna)) { return pDefaultValue; }
			
			return Convert.ToString(pRow[pColumna]);
		}


		public static XmlDocument GetXml(DataRow pRow, string pColumn, string pUseMainElement = null)
		{
			string xmlContents;

			XmlDocument result;


			xmlContents = GetString(pRow, pColumn);

			if (string.IsNullOrWhiteSpace(xmlContents))
			{
				return null;
			}

			result = new XmlDocument();

			if (pUseMainElement != null)
			{
				xmlContents = "<" + pUseMainElement + ">" + xmlContents + "</" + pUseMainElement + ">";
			}

			result.LoadXml(xmlContents);

			return result;
		}
		
		
		public static byte GetByte (DataRow pRow, string pColumna, Byte pNullValue)
		{
			object result;
		
		
			if (GetValue (pRow, pColumna, out result))
			{
				try
				{
					return Convert.ToByte (result);
				}
				catch (Exception)
				{
					return pNullValue;
				}
			}
			
			return pNullValue;
		}
		
		
		public static Byte? GetNullableByte (DataRow pRow, string pColumna)
		{
			object result;
		
		
			if (GetValue (pRow, pColumna, out result))
			{
				try
				{
					return Convert.ToByte (result);
				}
				catch (Exception)
				{
					return null;
				}
			}
			
			return null;
		}
		
		
		public static bool GetBool (DataRow pRow, string pColumna, bool pNullValue = false)
		{
			if (IsEmpty (pRow, pColumna)) { return pNullValue; }
			
			return TextHelper.GetBool (Convert.ToString(pRow[pColumna]));
		}
		
		
		public static bool? GetNullableBool (DataRow pRow, string pColumna)
		{
			if (IsEmpty (pRow, pColumna)) { return null; }
			
			return TextHelper.GetBool (Convert.ToString(pRow[pColumna]));
		}	
		
		
		public static bool GetValue (DataRow pRow, string pColumna, out object pValue)
		{
			if (pRow == null) { pValue = null; return false; }
			
			else if (pRow.Table.Columns [pColumna] == null) { pValue = null; return false; }
			
			else if (pRow.IsNull(pColumna)) { pValue = null; return false; }
			
			pValue = pRow [pColumna];
			
			return true;
		}
		
		#endregion
		
		
		#region Interval
		
		public static DataTable GetInterval (DataTable pTable, int pPageIndex, int pPageSize,
			out int pPageCount, out int pRowCount)
		{
			int startIndex;
			int intIndiceFinal;

			DataTable result;


			pPageCount = 0;
			pRowCount = 0;

			if (IsEmpty (pTable))
			{	
				return null;
			}
			
			if (pPageIndex == 0) { pPageIndex = 1; }

			startIndex = (pPageIndex - 1) * pPageSize;

			intIndiceFinal = startIndex + pPageSize - 1;

			pRowCount = pTable.Rows.Count;

			// Si no hay suficientes filas para mostrar la pagina solicitada (limite inferior del intervalo)
			if (startIndex > 0 && pTable.Rows.Count < startIndex - 1)
			{
				return null;
			}
			
			// Si no hay suficientes filas para mostrar la pagina solicitada (limite superior del intervalo)
			// Se ajusta el limite superior para permitir extraer la pagina solicitada
			if (pTable.Rows.Count < intIndiceFinal + 1)
			{
				intIndiceFinal = pTable.Rows.Count - 1;
			}
			
			result = pTable.Clone ();
			
			for (; startIndex <= intIndiceFinal; startIndex++)
			{
				result.ImportRow (pTable.Rows [(int) startIndex]);
			}

			pPageCount = (int) Math.Ceiling ((double) pTable.Rows.Count / (double) pPageSize);

			return result;
		}
		
		#endregion


		#region Linq

		//used by LINQ to SQL
		public static IQueryable<TSource> Page<TSource>(this IQueryable<TSource> source, int page, int pageSize)
		{
			return source.Skip((page - 1)*pageSize).Take(pageSize);
		}

		//used by LINQ
		public static IEnumerable<TSource> Page<TSource>(this IEnumerable<TSource> source, int page, int pageSize)
		{
			return source.Skip((page - 1)*pageSize).Take(pageSize);
		}

		#endregion
	}
}
